<?php

// 测试
$image = new Image();
// 测试水印
// $image->watermark('origin.jpeg', 'shuiyin.jpg', 1);
// 测试缩放
$image->scale('origin.jpeg', 300, 300);

// 图像处理类（水印，缩放）
class Image
{
    // 路径
    protected $path;
    // 是否启用随机名字
    protected $isRandName;
    // 要保存的图像类型
    protected $type;

    // 对成员属性进行初始化
    function __construct($path = './', $isRandName = true, $type = 'png')
    {
        $this->path = $path;
        $this->isRandName = $isRandName;
        $this->type = $type;
    }

    // 添加水印
    // $image: 图片路径
    // $water: 水印图片
    // $position: 水印放置位置
    // $trans: 透明度
    // $prefix: 前缀
    public function watermark($image, $water, $position, $trans = 100, $prefix = 'water_')
    {
        // 判断两个图片是否存在
        if (!file_exists($image) || !file_exists($water)) {
            die('图片资源不存在');
        }
        // 得到原图片的宽高和水印图片的宽高
        $imageInfo = self::getImageInfo($image);
        $waterInfo = self::getImageInfo($water);
        // 判断水印图片能否贴上来
        if (!$this->canWater($imageInfo, $waterInfo)) {
            die('水印图片太大');
        }
        // 打开图片
        $imageRes = self::openAnyImage($image);
        $waterRes = self::openAnyImage($water);
        // 根据水印图片的位置计算水印图片的坐标
        $pos = $this->getPosition($position, $imageInfo, $waterInfo);
        // 将水印图片贴过来
        imagecopymerge($imageRes, $waterRes, $pos['x'], $pos['y'], 0, 0, $waterInfo['width'], $waterInfo['height'], $trans);
        // 得到要保存图片的文件名
        $newName = $this->createNewName($image, $prefix);
        // 得到保存图片的路径
        $newPath = rtrim($this->path, '/') . '/' . $newName;
        // 保存图片
        $this->saveImage($imageRes, $newPath);
        // 销毁资源
        imagedestroy($imageRes);
        imagedestroy($waterRes);

        return $newPath;
    }

    // 缩放
    // $image: 需要缩放的图片
    // $width: 缩放后的宽度
    // $height: 缩放后的高度
    // $prefix: 前缀 
    public function scale($image, $width, $height, $prefix = 'scale_')
    {
        // 得到图片原来的宽高
        $imageInfo = self::getImageInfo($image);
        // 根据图片原来的宽高和最终要缩放的宽高计算得到图像不变性的宽高
        $size = $this->getNewSize($width, $height, $imageInfo);
        // 打开图片资源
        $imageRes = self::openAnyImage($image);
        // 进行缩放
        $newImageRes = $this->kidOfImage($imageRes, $size, $imageInfo);
        // 得到要保存图片的文件名
        $newName = $this->createNewName($image, $prefix);
        // 得到保存图片的路径
        $newPath = rtrim($this->path, '/') . '/' . $newName;
        // 保存图片
        $this->saveImage($newImageRes, $newPath);
        // 销毁图片资源
        imagedestroy($imageRes);
        imagedestroy($newImageRes);

        return $newPath;
    }

    // 判断水印图片能否贴上来
    protected function canWater($imageInfo, $waterInfo)
    {
        if (($waterInfo['width'] > $imageInfo['width']) || ($waterInfo['height'] > $imageInfo['height'])) {
            return false;
        }
        return true;
    }

    // 计算水印图片位置
    protected function getPosition($position, $imageInfo, $waterInfo)
    {
        switch ($position) {
            case 1:
                $x = 0;
                $y = 0;
                break;
            case 2:
                $x = ($imageInfo['width'] - $waterInfo['width']) / 2;
                $y = 0;
                break;
            case 3:
                $x = $imageInfo['width'] - $waterInfo['width'];
                $y = 0;
                break;
            case 4:
                $x = 0;
                $y = ($imageInfo['height'] - $waterInfo['height']) / 2;
                break;
            case 5:
                $x = ($imageInfo['width'] - $waterInfo['width']) / 2;
                $y = ($imageInfo['height'] - $waterInfo['height']) / 2;
                break;
            case 6:
                $x = $imageInfo['width'] - $waterInfo['width'];
                $y = ($imageInfo['height'] - $waterInfo['height']) / 2;
                break;
            case 7:
                $x = 0;
                $y = $imageInfo['height'] - $waterInfo['height'];
                break;
            case 8:
                $x = ($imageInfo['width'] - $waterInfo['width']) / 2;
                $y = $imageInfo['height'] - $waterInfo['height'];
                break;
            case 9:
                $x = $imageInfo['width'] - $waterInfo['width'];
                $y = $imageInfo['height'] - $waterInfo['height'];
                break;
            case 0:
                $x = mt_rand(0, ($imageInfo['width'] - $waterInfo['width']));
                $y = mt_rand(0, ($imageInfo['height'] - $waterInfo['height']));
                break;
        }
        return ['x' => $x, 'y' => $y];
    }

    // 得到新的文件名
    protected function createNewName($imagePath, $prefix)
    {
        // 如果启用随机名字
        if ($this->isRandName) {
            $name = $prefix . uniqid() . '.' . $this->type;
        } else {
            $name = $prefix . pathinfo($imagePath)['filename'] . $this->type;
        }
        return $name;
    }

    // 处理透明色函数
    protected function kidOfImage($srcImage, $size, $imageInfo)
    {
        // 传入新的尺寸，创建一个指定尺寸的图片
        $newImage = imagecreatetruecolor($size['old_w'], $size['old_h']);
        // 定义透明色
        $otsc = imagecolortransparent($srcImage);
        if ($otsc >= 0) {
            // 取得透明色
            $transparentcolor = imagecolorsforindex($srcImage, $otsc);
            // 创建透明色
            $newtransparentcolor = imagecolorallocate(
                $newImage,
                $transparentcolor['red'],
                $transparentcolor['green'],
                $transparentcolor['blue']
            );
        } else {
            // 将黑色作为透明色，因为创建图像后在第一次分配颜色时背景默认为黑色
            $newtransparentcolor = imagecolorallocate($newImage, 0, 0, 0);
        }
        // 背景填充透明
        imagefill($newImage, 0, 0, $newtransparentcolor);
        imagecolortransparent($newImage, $newtransparentcolor);

        imagecopyresampled(
            $newImage,
            $srcImage,
            $size['x'],
            $size['y'],
            0,
            0,
            $size['new_w'],
            $size['new_h'],
            $imageInfo['width'],
            $imageInfo['height']
        );
        return $newImage;
    }

    // 计算宽高
    // $width: 最终缩放的宽度
    // $height: 最终缩放的高度
    // $imageInfo: 原始图片的宽高
    protected function getNewSize($width, $height, $imageInfo)
    {
        $size['old_w'] = $width;
        $size['old_h'] = $height;

        $scaleWidth  = $width / $imageInfo['width'];
        $scaleHeight = $height / $imageInfo['height'];
        $scaleFinal = min($scaleWidth, $scaleHeight);

        $size['new_w'] = round($imageInfo['width'] * $scaleFinal);
        $size['new_h'] = round($imageInfo['height'] * $scaleFinal);
        if ($scaleWidth < $scaleHeight) {
            $size['x'] = 0;
            $size['y'] = round(abs($size['new_h'] - $height) / 2);
        } else {
            $size['x'] = round(abs($size['new_w'] - $width) / 2);
            $size['y'] = 0;
        }

        return $size;
    }

    // 保存图片
    public function saveImage($imageRes, $newPath)
    {
        $func = 'image' . $this->type;
        // 通过变量函数保存
        $func($imageRes, $newPath);
    }

    // 根据图片路径获取图片信息（宽高、mime）
    static function getImageInfo($imagePath)
    {
        $info = getimagesize($imagePath);
        $data['width'] = $info[0];
        $data['height'] = $info[1];
        $data['mime'] = $info['mime'];
        return $data;
    }

    // 打开图片
    static function openAnyImage($imagePath)
    {
        // 得到图像的 mime 类型
        $mime = self::getImageInfo($imagePath)['mime'];

        // 根据不同的mime类型打开图像
        switch ($mime) {
            case 'image/png':
                $image = imagecreatefrompng($imagePath);
                break;
            case 'image/gif':
                $image = imagecreatefromgif($imagePath);
                break;
            case 'image/jpeg':
                $image = imagecreatefromjpeg($imagePath);
                break;
            case 'image/wbmp':
                $image = imagecreatefromwbmp($imagePath);
                break;
        }
        return $image;
    }
}
